from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import or_, func, select
from typing import List, Optional
from app.models.database import get_db
from app.models.note import Note, NoteVersion, note_documents
from app.models.document import Document
from app.models.knowledge_base import KnowledgeBase
from app.models.user import User
from app.schemas.note import (
    NoteCreate, NoteUpdate, NoteResponse, NoteListItem, 
    NoteVersionResponse, NoteVectorizeRequest, NoteSaveToRequest,
    NoteDocumentInfo
)
from app.api.auth import get_current_user
from app.services.vector_store import VectorStore, get_embedding_dimension
from app.services.document_processor import DocumentProcessor
from app.core.config import settings
import uuid
import json
import logging
import os

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/notes", tags=["notes"])


@router.post("/", response_model=NoteResponse)
async def create_note(
    note: NoteCreate,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """创建笔记"""
    try:
        # 计算字数
        word_count = len(note.content)
        
        # 创建笔记
        new_note = Note(
            id=str(uuid.uuid4()),
            title=note.title,
            content=note.content,
            owner_id=user.id,
            owner_name=user.full_name or user.username,
            knowledge_base_id=note.knowledge_base_id,
            word_count=word_count,
            extra_metadata=json.dumps(note.metadata) if note.metadata else None
        )
        
        # 如果指定了知识库，设置为公开
        if note.knowledge_base_id:
            new_note.is_public = True
        
        db.add(new_note)
        db.flush()  # 获取ID但不提交
        
        # 关联文档
        for doc_id in note.document_ids:
            # 检查文档是否存在
            doc = db.query(Document).filter(Document.id == doc_id).first()
            if doc:
                db.execute(
                    note_documents.insert().values(
                        id=str(uuid.uuid4()),
                        note_id=new_note.id,
                        document_id=doc_id
                    )
                )
        
        # 创建初始版本
        version = NoteVersion(
            id=str(uuid.uuid4()),
            note_id=new_note.id,
            title=note.title,
            content=note.content,
            version_number=1,
            created_by=user.id
        )
        db.add(version)
        
        db.commit()
        db.refresh(new_note)
        
        logger.info(f"用户 {user.username} 创建笔记: {new_note.title}")
        
        # 获取关联文档数量
        doc_count = db.query(func.count(note_documents.c.id)).filter(
            note_documents.c.note_id == new_note.id
        ).scalar()
        
        # 获取关联文档列表
        docs = db.query(Document).join(
            note_documents, Document.id == note_documents.c.document_id
        ).filter(note_documents.c.note_id == new_note.id).all()
        
        response = NoteResponse.model_validate(new_note)
        response.document_count = doc_count
        response.documents = [NoteDocumentInfo.model_validate(doc) for doc in docs]
        
        return response
        
    except Exception as e:
        db.rollback()
        logger.error(f"创建笔记失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"创建笔记失败: {str(e)}")


@router.get("/", response_model=List[NoteListItem])
async def list_notes(
    search: Optional[str] = None,
    knowledge_base_id: Optional[str] = None,
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=100),
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """获取笔记列表（仅显示自己的笔记）"""
    try:
        query = db.query(Note).filter(Note.owner_id == user.id)
        
        if search:
            query = query.filter(
                or_(
                    Note.title.ilike(f"%{search}%"),
                    Note.content.ilike(f"%{search}%")
                )
            )
        
        if knowledge_base_id:
            query = query.filter(Note.knowledge_base_id == knowledge_base_id)
        
        total = query.count()
        notes = query.order_by(Note.updated_at.desc(), Note.created_at.desc()).offset(skip).limit(limit).all()
        
        # 转换为列表项（包含内容预览）
        result = []
        for note in notes:
            # 获取文档数量
            doc_count = db.query(func.count(note_documents.c.id)).filter(
                note_documents.c.note_id == note.id
            ).scalar()
            
            # 内容预览（前200字）
            content_preview = note.content[:200] + "..." if len(note.content) > 200 else note.content
            
            item = NoteListItem(
                id=note.id,
                title=note.title,
                content_preview=content_preview,
                owner_id=note.owner_id,
                owner_name=note.owner_name,
                knowledge_base_id=note.knowledge_base_id,
                is_vectorized=note.is_vectorized,
                is_public=note.is_public,
                word_count=note.word_count,
                created_at=note.created_at,
                updated_at=note.updated_at,
                document_count=doc_count
            )
            result.append(item)
        
        logger.info(f"用户 {user.username} 查询笔记列表: 共 {total} 条，返回 {len(result)} 条")
        return result
        
    except Exception as e:
        logger.error(f"获取笔记列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取笔记列表失败: {str(e)}")


@router.get("/{note_id}", response_model=NoteResponse)
async def get_note(
    note_id: str,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """获取笔记详情"""
    note = db.query(Note).filter(
        Note.id == note_id,
        Note.owner_id == user.id
    ).first()
    
    if not note:
        raise HTTPException(status_code=404, detail="笔记不存在")
    
    # 获取关联文档数量和列表
    doc_count = db.query(func.count(note_documents.c.id)).filter(
        note_documents.c.note_id == note.id
    ).scalar()
    
    docs = db.query(Document).join(
        note_documents, Document.id == note_documents.c.document_id
    ).filter(note_documents.c.note_id == note.id).all()
    
    response = NoteResponse.model_validate(note)
    response.document_count = doc_count
    response.documents = [NoteDocumentInfo.model_validate(doc) for doc in docs]
    
    return response


@router.put("/{note_id}", response_model=NoteResponse)
async def update_note(
    note_id: str,
    note_update: NoteUpdate,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """更新笔记"""
    try:
        note = db.query(Note).filter(
            Note.id == note_id,
            Note.owner_id == user.id
        ).first()
        
        if not note:
            raise HTTPException(status_code=404, detail="笔记不存在")
        
        # 获取当前版本号
        latest_version = db.query(func.max(NoteVersion.version_number)).filter(
            NoteVersion.note_id == note_id
        ).scalar() or 0
        
        # 更新字段
        updated = False
        if note_update.title is not None:
            note.title = note_update.title
            updated = True
        if note_update.content is not None:
            note.content = note_update.content
            note.word_count = len(note_update.content)
            updated = True
        if note_update.knowledge_base_id is not None:
            note.knowledge_base_id = note_update.knowledge_base_id
            note.is_public = bool(note_update.knowledge_base_id)
            updated = True
        
        # 更新文档关联
        if note_update.document_ids is not None:
            # 删除旧关联
            db.execute(
                note_documents.delete().where(note_documents.c.note_id == note_id)
            )
            # 添加新关联
            for doc_id in note_update.document_ids:
                doc = db.query(Document).filter(Document.id == doc_id).first()
                if doc:
                    db.execute(
                        note_documents.insert().values(
                            id=str(uuid.uuid4()),
                            note_id=note_id,
                            document_id=doc_id
                        )
                    )
            updated = True
        
        # 如果有更新，创建新版本
        if updated:
            new_version = NoteVersion(
                id=str(uuid.uuid4()),
                note_id=note_id,
                title=note.title,
                content=note.content,
                version_number=latest_version + 1,
                created_by=user.id
            )
            db.add(new_version)
        
        db.commit()
        db.refresh(note)
        
        logger.info(f"用户 {user.username} 更新笔记: {note.title}")
        
        # 获取关联文档
        doc_count = db.query(func.count(note_documents.c.id)).filter(
            note_documents.c.note_id == note.id
        ).scalar()
        
        docs = db.query(Document).join(
            note_documents, Document.id == note_documents.c.document_id
        ).filter(note_documents.c.note_id == note.id).all()
        
        response = NoteResponse.model_validate(note)
        response.document_count = doc_count
        response.documents = [NoteDocumentInfo.model_validate(doc) for doc in docs]
        
        return response
        
    except Exception as e:
        db.rollback()
        logger.error(f"更新笔记失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"更新笔记失败: {str(e)}")


@router.delete("/{note_id}")
async def delete_note(
    note_id: str,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """删除笔记"""
    try:
        note = db.query(Note).filter(
            Note.id == note_id,
            Note.owner_id == user.id
        ).first()
        
        if not note:
            raise HTTPException(status_code=404, detail="笔记不存在")
        
        title = note.title
        
        # 删除笔记（关联表和版本会通过 CASCADE 自动删除）
        db.delete(note)
        db.commit()
        
        logger.info(f"用户 {user.username} 删除笔记: {title}")
        
        return {"message": "笔记删除成功"}
        
    except Exception as e:
        db.rollback()
        logger.error(f"删除笔记失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"删除笔记失败: {str(e)}")


@router.post("/save-from-chat", response_model=NoteResponse)
async def save_from_chat(
    request: NoteSaveToRequest,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """从RAG问答保存到笔记"""
    try:
        if request.note_id:
            # 追加到已有笔记
            note = db.query(Note).filter(
                Note.id == request.note_id,
                Note.owner_id == user.id
            ).first()
            
            if not note:
                raise HTTPException(status_code=404, detail="笔记不存在")
            
            # 获取当前版本号
            latest_version = db.query(func.max(NoteVersion.version_number)).filter(
                NoteVersion.note_id == request.note_id
            ).scalar() or 0
            
            # 追加内容
            note.content += f"\n\n---\n\n{request.content}"
            note.word_count = len(note.content)
            
            # 创建新版本
            new_version = NoteVersion(
                id=str(uuid.uuid4()),
                note_id=request.note_id,
                title=note.title,
                content=note.content,
                version_number=latest_version + 1,
                created_by=user.id
            )
            db.add(new_version)
            
            db.commit()
            db.refresh(note)
            
            logger.info(f"用户 {user.username} 追加内容到笔记: {note.title}")
            
        else:
            # 创建新笔记
            note_data = NoteCreate(
                title=request.title,
                content=request.content,
                document_ids=request.document_ids,
                metadata=request.metadata
            )
            return await create_note(note_data, db, user)
        
        # 获取关联文档
        doc_count = db.query(func.count(note_documents.c.id)).filter(
            note_documents.c.note_id == note.id
        ).scalar()
        
        docs = db.query(Document).join(
            note_documents, Document.id == note_documents.c.document_id
        ).filter(note_documents.c.note_id == note.id).all()
        
        response = NoteResponse.model_validate(note)
        response.document_count = doc_count
        response.documents = [NoteDocumentInfo.model_validate(doc) for doc in docs]
        
        return response
        
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"保存到笔记失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"保存到笔记失败: {str(e)}")


@router.get("/{note_id}/versions", response_model=List[NoteVersionResponse])
async def get_note_versions(
    note_id: str,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """获取笔记历史版本"""
    # 检查笔记是否属于当前用户
    note = db.query(Note).filter(
        Note.id == note_id,
        Note.owner_id == user.id
    ).first()
    
    if not note:
        raise HTTPException(status_code=404, detail="笔记不存在")
    
    # 获取所有版本，按版本号降序排列
    versions = db.query(NoteVersion).filter(
        NoteVersion.note_id == note_id
    ).order_by(NoteVersion.version_number.desc()).all()
    
    logger.info(f"用户 {user.username} 查询笔记 {note.title} 的历史版本，共 {len(versions)} 个")
    
    return [NoteVersionResponse.model_validate(v) for v in versions]


@router.post("/{note_id}/restore/{version_number}", response_model=NoteResponse)
async def restore_note_version(
    note_id: str,
    version_number: int,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """恢复到指定版本"""
    try:
        # 检查笔记是否属于当前用户
        note = db.query(Note).filter(
            Note.id == note_id,
            Note.owner_id == user.id
        ).first()
        
        if not note:
            raise HTTPException(status_code=404, detail="笔记不存在")
        
        # 获取指定版本
        target_version = db.query(NoteVersion).filter(
            NoteVersion.note_id == note_id,
            NoteVersion.version_number == version_number
        ).first()
        
        if not target_version:
            raise HTTPException(status_code=404, detail="版本不存在")
        
        # 获取当前最新版本号
        latest_version_number = db.query(func.max(NoteVersion.version_number)).filter(
            NoteVersion.note_id == note_id
        ).scalar() or 0
        
        # 恢复内容到笔记
        note.title = target_version.title
        note.content = target_version.content
        note.word_count = len(target_version.content)
        
        # 创建新版本（标记为恢复）
        new_version = NoteVersion(
            id=str(uuid.uuid4()),
            note_id=note_id,
            title=target_version.title,
            content=target_version.content,
            version_number=latest_version_number + 1,
            created_by=user.id
        )
        db.add(new_version)
        
        db.commit()
        db.refresh(note)
        
        logger.info(f"用户 {user.username} 将笔记 {note.title} 恢复到版本 {version_number}")
        
        # 获取关联文档
        doc_count = db.query(func.count(note_documents.c.id)).filter(
            note_documents.c.note_id == note.id
        ).scalar()
        
        docs = db.query(Document).join(
            note_documents, Document.id == note_documents.c.document_id
        ).filter(note_documents.c.note_id == note.id).all()
        
        response = NoteResponse.model_validate(note)
        response.document_count = doc_count
        response.documents = [NoteDocumentInfo.model_validate(doc) for doc in docs]
        
        return response
        
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"恢复笔记版本失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"恢复笔记版本失败: {str(e)}")


@router.post("/{note_id}/vectorize")
async def vectorize_note(
    note_id: str,
    request: NoteVectorizeRequest,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user)
):
    """向量化笔记（加入知识库）"""
    try:
        # 检查笔记是否属于当前用户
        note = db.query(Note).filter(
            Note.id == note_id,
            Note.owner_id == user.id
        ).first()
        
        if not note:
            raise HTTPException(status_code=404, detail="笔记不存在")
        
        # 检查知识库是否存在
        kb = db.query(KnowledgeBase).filter(
            KnowledgeBase.id == request.knowledge_base_id
        ).first()
        
        if not kb:
            raise HTTPException(status_code=404, detail="知识库不存在")
        
        logger.info(f"开始向量化笔记: {note.title} -> 知识库: {kb.name}")
        
        # 更新笔记的知识库关联
        note.knowledge_base_id = request.knowledge_base_id
        note.is_public = True  # 加入知识库后变为公开
        
        # 使用文档处理器对笔记内容进行分块
        processor = DocumentProcessor()
        chunks = processor.chunk_text(note.content, chunk_size=500, overlap=50)
        
        logger.info(f"笔记内容分块完成，共 {len(chunks)} 个片段")
        
        # 初始化或加载向量存储
        vector_path = os.path.join(settings.UPLOAD_DIR, "vectors", kb.id)
        dimension = get_embedding_dimension(settings.OLLAMA_EMBED_MODEL)
        
        if os.path.exists(f"{vector_path}.index"):
            # 加载现有向量库
            vector_store = VectorStore(dimension=dimension)
            vector_store.load(vector_path)
            logger.info(f"加载现有向量库: {vector_path}")
        else:
            # 创建新向量库
            vector_store = VectorStore(dimension=dimension)
            logger.info(f"创建新向量库: {vector_path}")
        
        # 生成向量并添加到向量库
        from app.services.ollama_client import OllamaClient
        ollama_client = OllamaClient()
        
        texts_to_add = []
        metadatas = []
        
        for i, chunk in enumerate(chunks):
            texts_to_add.append(chunk)
            metadatas.append({
                "source": "note",
                "note_id": note.id,
                "note_title": note.title,
                "chunk_index": i,
                "total_chunks": len(chunks),
                "owner_id": note.owner_id,
                "owner_name": note.owner_name
            })
        
        # 批量生成向量
        logger.info(f"开始生成向量，共 {len(texts_to_add)} 个片段")
        embeddings = []
        for text in texts_to_add:
            embedding = await ollama_client.generate_embedding(text)
            embeddings.append(embedding)
        
        # 添加到向量库
        vector_store.add_texts(texts_to_add, embeddings, metadatas)
        
        # 保存向量库
        vector_store.save(vector_path)
        logger.info(f"向量库保存成功: {vector_path}")
        
        # 更新笔记状态
        note.is_vectorized = True
        note.vector_store_id = kb.id
        
        # 更新知识库的文档数量（包含笔记）
        # 注意：这里简化处理，实际可能需要单独统计笔记数量
        
        db.commit()
        db.refresh(note)
        
        logger.info(f"笔记 {note.title} 向量化完成")
        
        return {
            "message": "笔记向量化成功",
            "note_id": note.id,
            "knowledge_base_id": kb.id,
            "chunks": len(chunks)
        }
        
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"向量化笔记失败: {str(e)}")
        import traceback
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"向量化笔记失败: {str(e)}")

